#pragma once

#include "Common.h"
#include "ThreadCache.h"
#include "PageCache.h"
#include "ObjectPool.h"

#ifdef _WIN32

//申请的空间 128*8页>= size > 256KB,仍然可以去线程池取内存,只不过是直接从pagecache上去取
//超过128*8KB就只能去堆上取了
static void* ConcurrentAlloc(size_t size)
{
    if (size > MAX_BYTES)
    {
        size_t alignSize = SizeClass::RoundUp(size);//获得对齐之后的数
        size_t kpage = alignSize >> PAGE_SHIFT;     //获得页数(该size需要多少个页)

        PageCache::GetInstance()->_pageMtx.lock();
        Span* span = PageCache::GetInstance()->NewSpan(kpage);   //去获得kpage页回来    
        span->_objSize = size;
        PageCache::GetInstance()->_pageMtx.unlock();

        void* ptr = (void*)(span->_pageId << PAGE_SHIFT);
        return ptr;
    }
    //通过TLS 每个线程无锁的获取自己的专属ThreadCache指针变量
    if (pTLSThreadCache == nullptr)
    {
        static ObjectPool<ThreadCache> TcPool;
        // pTLSThreadCache = new ThreadCache;
        pTLSThreadCache = TcPool.New();
    }

    // cout << std::this_thread::get_id() << ": " << pTLSThreadChche << endl;

    return pTLSThreadCache->Allocate(size);
}

//释放
static void ConcurrentFree(void* ptr /*, size_t size*/)
{
    //如何不用size, 判断传进来的ptr(内存起始空间有多大?)
    //用地址算出所属的页号,通过页号能找出所属的span(map)(在span里面增加一个size的大小即可)
    assert(pTLSThreadCache);
    Span* span = PageCache::GetInstance()->MapObjectToSpan(ptr);
    size_t size = span->_objSize;

    //先找到span确认是要返回堆还是返回pagecache
    //小于128页的空间还是能放回给线程池的,如果大于这个数就只能还给系统了
    if (size > MAX_BYTES)
    {
        PageCache::GetInstance()->_pageMtx.lock();
        PageCache::GetInstance()->ReleaseSpanToPageCache(span);
        PageCache::GetInstance()->_pageMtx.unlock();

    }
    pTLSThreadCache->Deallocate(ptr, size);
}

#endif
